import type {
    UniversalFlowNode,
    UniversalFlowEdge,
    UniversalFlowNodeData,
    NodeSemanticType
} from '@/models/universalFlow';
import { v4 as uuidv4 } from 'uuid';
import type { ParseUniversalResult } from '../universalParser';

// --- Internal Transformation Logic --- 

interface TransformJsResult {
    nodes: UniversalFlowNode[];
    edges: UniversalFlowEdge[];
    rootId: string | null;
}

/**
 * Transforms the JavaScript object/array structure from JSON.parse()
 * into the Universal Flow format.
 *
 * @param rootJsData The root JS object or array.
 * @returns An object containing the extracted nodes, edges, and the root ID.
 */
function transformJsObjectToUniversal(rootJsData: any): TransformJsResult {
    const nodes: UniversalFlowNode[] = [];
    const edges: UniversalFlowEdge[] = [];
    let rootId: string | null = null;

    /**
     * Recursively processes a JS value (object, array, or primitive).
     *
     * @param jsData The current JS value.
     * @param key The key (for object properties) or index (for array elements) or null (for root).
     * @param parentUniversalId The ID of the parent UniversalFlowNode (or null if root).
     * @param level The current depth level.
     * @param order The order among siblings.
     * @param parentPath The path of the parent node.
     * @returns The unique ID generated for the created UniversalFlowNode, or null if primitive was handled directly by parent.
     */
    function traverse(jsData: any, key: string | number | null, parentUniversalId: string | null, level: number, order: number, parentPath: string): string | null {
        let currentUniversalId: string | null = null;
        let currentNodePath: string = '';
        let nodeSemanticType: NodeSemanticType | null = null;
        const nodeName = key !== null ? String(key) : ''; // Use key/index as name

        // Determine Path Segment
        let pathSegment: string;
        if (key === null) { // Root
            pathSegment = '';
        } else if (typeof key === 'number') { // Array Index
            pathSegment = `[${key}]`;
        } else { // Object Key
            // Basic handling for keys, might need escaping if keys have special chars
            pathSegment = key.includes('.') || key.includes('[') ? `['${key}'']` : `.${key}`;
        }
        currentNodePath = parentPath + pathSegment;

        // Determine Semantic Type and Create Node
        if (Array.isArray(jsData)) {
            nodeSemanticType = 'array';
            currentUniversalId = uuidv4();
            const nodeData: UniversalFlowNodeData = {
                sourceElement: jsData, // Keep reference
                name: nodeName,
                nodeSemanticType: nodeSemanticType,
                attributes: {}, // JSON arrays don't have attributes in the XML sense
                format: 'json', 
                path: currentNodePath,
                level: level,
                order: order,
                childrenIds: [],
            };
            nodes.push({
                id: currentUniversalId,
                type: 'universal',
                data: nodeData,
                position: { x: 0, y: 0 },
            });

            // Traverse array elements
            let childOrder = 0;
            jsData.forEach((item, index) => {
                const childId = traverse(item, index, currentUniversalId, level + 1, childOrder, currentNodePath);
                if (childId && nodeData.childrenIds) {
                    nodeData.childrenIds.push(childId);
                    childOrder++;
                }
            });

        } else if (typeof jsData === 'object' && jsData !== null) {
            nodeSemanticType = 'object';
            currentUniversalId = uuidv4();
            const nodeData: UniversalFlowNodeData = {
                sourceElement: jsData,
                name: nodeName,
                nodeSemanticType: nodeSemanticType,
                attributes: {}, // JSON objects don't have attributes
                format: 'json',
                path: currentNodePath,
                level: level,
                order: order,
                childrenIds: [],
            };
            nodes.push({
                id: currentUniversalId,
                type: 'universal',
                data: nodeData,
                position: { x: 0, y: 0 },
            });

            // Traverse object properties
            let childOrder = 0;
            Object.entries(jsData).forEach(([propKey, propValue]) => {
                const childId = traverse(propValue, propKey, currentUniversalId, level + 1, childOrder, currentNodePath);
                if (childId && nodeData.childrenIds) {
                    nodeData.childrenIds.push(childId);
                    childOrder++;
                }
            });

        } else { // Primitive value (string, number, boolean, null)
            nodeSemanticType = 'value';
            currentUniversalId = uuidv4();
            const nodeData: UniversalFlowNodeData = {
                sourceElement: jsData,
                name: nodeName,
                value: jsData, // Store the primitive value
                nodeSemanticType: nodeSemanticType,
                attributes: {},
                format: 'json',
                path: currentNodePath,
                level: level,
                order: order,
            };
             nodes.push({
                id: currentUniversalId,
                type: 'universal',
                data: nodeData,
                position: { x: 0, y: 0 },
            });
        }

        // Set rootId and root node type
        if (parentUniversalId === null) {
            rootId = currentUniversalId;
            if (currentUniversalId) {
                const rootNode = nodes.find(n => n.id === currentUniversalId);
                if (rootNode?.data) {
                    rootNode.data.nodeSemanticType = 'root'; // Overwrite type for the actual root
                }
            }
        } else if (currentUniversalId) {
            // Create Edge to Parent if not root and node was created
            edges.push({
                id: uuidv4(),
                source: parentUniversalId,
                target: currentUniversalId,
                type: 'smoothstep',
                data: { relationshipType: 'parent-child' },
            });
        }

        return currentUniversalId;
    }

    // Start traversal from the root JavaScript data
    traverse(rootJsData, null, null, 0, 0, '$'); // Use '$' as the root path indicator

    return { nodes, edges, rootId };
}


/**
 * Parses a JSON string into Universal Flow format.
 *
 * @param content The JSON string content.
 * @returns A ParseUniversalResult object containing UniversalFlowNodes and Edges.
 */
export function parse(content: string): ParseUniversalResult {
    let parsedData: any;

    // --- Step 1: Parse JSON string --- 
    try {
        parsedData = JSON.parse(content);
    } catch (err: any) {
        console.error('[jsonUniversalParser] JSON Parsing Error:', err);
        // Try to provide a more user-friendly error message
        let errorMessage = `JSON Parsing Error: ${err.message}`;
        // Example of trying to extract line/column (might not work reliably for all JSON parse errors)
        const positionMatch = err.message.match(/at position (\d+)/);
        if (positionMatch) {
            const position = parseInt(positionMatch[1], 10);
            let line = 1;
            let column = 1;
            for (let i = 0; i < position && i < content.length; i++) {
                if (content[i] === '\n') {
                    line++;
                    column = 1;
                } else {
                    column++;
                }
            }
            errorMessage += ` (near Line: ${line}, Col: ${column})`;
        }
        return {
            success: false,
            error: errorMessage,
            nodes: [],
            edges: [],
            rootId: null,
        };
    }

    // --- Step 2: Transform JS Object/Array to Universal Flow Format ---
    try {
        const transformResult = transformJsObjectToUniversal(parsedData);

        return {
            success: true,
            nodes: transformResult.nodes,
            edges: transformResult.edges,
            rootId: transformResult.rootId,
            rawDocument: parsedData // Store the parsed JS object
        };
    } catch (transformError: any) {
        console.error('[jsonUniversalParser] Error during transformation:', transformError);
        return {
            success: false,
            error: `Transformation Error: ${transformError.message || 'Unknown error'}`,
            nodes: [],
            edges: [],
            rootId: null,
        };
    }
} 